package com.ting.test.util;

import com.ting.test.CommonConstant;
import com.ting.test.enums.ChannelEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * @author 雷霆
 * @version 1.0.0  ConcurrentHashMapUtil 线程安全 map 缓存
 * @date$ 2018/1/20
 *
 * Description：
 *
 * Modification History:
 *
 */
@Slf4j
public class ConcurrentHashMapUtil {

    private static ConcurrentHashMap<String,Integer> cache=new ConcurrentHashMap<String,Integer>();

    private static final ReentrantLock mainLock = new ReentrantLock();

    /**
     * 初始化map,同时，启动刷新缓存线程
     */
    static {
        init();

        Thread  cacheThread = new Thread(new CacheRunner());
        cacheThread.setName("cacheThread");
        cacheThread.start();
    }

    /**
     * 判断是否允许向该渠道发送请求
     * @param channel
     * @return
     */
    public static boolean isAllowed(ChannelEnum channel){
        final ReentrantLock lock = mainLock;
        try {
            lock.lock();
            Integer count = cache.get(channel.getCode());
            if(null==count){
                log.info("未获取到渠道号为{}的缓存",channel.getCode());
                return false;
            }
            if(count >= CommonConstant.ACCESS_LIMIT){
                //log.info("渠道号为{}的渠道当前已超过每秒最大访问量",channel.getCode());
                return false;
            }
            count++;
            cache.put(channel.getCode(),count);
            return true;
        }catch (Exception e){
            return false;
        }finally {
            lock.unlock();
        }

    }


    public static void init(){
        ReentrantLock lock=mainLock;
        try {
            lock.lock();
            //设置缓存初始值
            for(ChannelEnum channelEnum:ChannelEnum.values()){
                cache.put(channelEnum.getCode(),0);
            }
        }finally {
            lock.unlock();
        }

    }

    /**
     * 内部线程类 定时 每秒刷新一次缓存
     */
    private static class CacheRunner implements Runnable {

        private volatile boolean stopped = false;

        void shutdown() {
            this.stopped = true;
        }

        @Override
        public void run() {
            while (!this.stopped) {
                try {
                    Thread.sleep(1000);
                    init();
                }catch (Exception e){

                }
            }
        }

    }
}
